package com.xherorlclass.channelHandler.handler;

import com.xherorlclass.XherorlRpcBootstrap;
import com.xherorlclass.enumeration.RespCode;
import com.xherorlclass.exceptions.ResponseException;
import com.xherorlclass.loadbalancer.LoadBalancer;
import com.xherorlclass.protection.CircuitBreaker;
import com.xherorlclass.transport.message.XherorlRpcRequest;
import com.xherorlclass.transport.message.XherorlRpcResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.net.SocketAddress;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author ：Xherorl
 * @date ：Created in 2023/8/26 9:42
 * @description：
 */
@Slf4j
public class MySimpleChannelInboundHandler extends SimpleChannelInboundHandler<XherorlRpcResponse> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, XherorlRpcResponse xherorlRpcResponse) throws Exception {

        // 从全局的挂起的请求中寻找与之匹配的待处理的 completableFuture
        CompletableFuture<Object> completableFuture = XherorlRpcBootstrap.PENDING_REQUEST.get(xherorlRpcResponse.getRequestId());

        SocketAddress socketAddress = channelHandlerContext.channel().remoteAddress();
        Map<SocketAddress, CircuitBreaker> everyIpCircuitBreaker = XherorlRpcBootstrap.getInstance().getConfiguration().getEveryIpCircuitBreaker();
        CircuitBreaker circuitBreaker = everyIpCircuitBreaker.get(socketAddress);

        byte code = xherorlRpcResponse.getCode();
        if (code == RespCode.FAIL.getCode()){
            circuitBreaker.recordErrorRequest();
            completableFuture.complete(null);
            log.error("当前id为【{}】的请求，返回错误的结果，响应码【{}】。",
                    xherorlRpcResponse.getRequestId(),xherorlRpcResponse.getCode());
            throw new ResponseException(code,RespCode.FAIL.getDesc());
        }  else if (code == RespCode.RATE_LIMIT.getCode()){
            circuitBreaker.recordErrorRequest();
            completableFuture.complete(null);
            log.error("当前id为【{}】的请求，被限流，响应码【{}】。",
                    xherorlRpcResponse.getRequestId(),xherorlRpcResponse.getCode());
            throw new ResponseException(code,RespCode.RATE_LIMIT.getDesc());

        } else if (code == RespCode.RESOURCE_NOT_FOUND.getCode() ){
            circuitBreaker.recordErrorRequest();
            completableFuture.complete(null);
            log.error("当前id为【{}】的请求，未找到目标资源，响应码【{}】。",
                    xherorlRpcResponse.getRequestId(),xherorlRpcResponse.getCode());
            throw new ResponseException(code,RespCode.RESOURCE_NOT_FOUND.getDesc());

        } else if (code == RespCode.SUCCESS.getCode() ){
            // 服务提供方，给予的结果
            Object returnValue = xherorlRpcResponse.getBody();
            completableFuture.complete(returnValue);
            if (log.isDebugEnabled()) {
                log.debug("以寻找到编号为【{}】的completableFuture，处理响应结果。", xherorlRpcResponse.getRequestId());
            }
        } else if(code == RespCode.SUCCESS_HEART_BEAT.getCode()){
            completableFuture.complete(null);
            if (log.isDebugEnabled()) {
                log.debug("以寻找到编号为【{}】的completableFuture,处理心跳检测，处理响应结果。", xherorlRpcResponse.getRequestId());
            }
        } else if(code == RespCode.BECLOSING.getCode()){
            completableFuture.complete(null);
            if (log.isDebugEnabled()) {
                log.debug("当前id为【{}】的请求，访问被拒绝，目标服务器正处于关闭中，响应码【{}】。",
                        xherorlRpcResponse.getRequestId(),xherorlRpcResponse.getCode());
            }

            // 修正负载均衡器
            // 从健康列表中移除
            XherorlRpcBootstrap.CHANNEL_CACHE.remove(socketAddress);

            // reLoadBalance
            LoadBalancer loadBalancer = XherorlRpcBootstrap.getInstance().getConfiguration().getLoadBalancer();

            // 重新进行负载均衡
            XherorlRpcRequest xherorlRpcRequest = XherorlRpcBootstrap.REQUEST_THREAD_LOCAL.get();
            loadBalancer.reLoadBalance(xherorlRpcRequest.getRequestPayload().getInterfaceName(), XherorlRpcBootstrap.CHANNEL_CACHE.keySet().stream().collect(Collectors.toList()));

            throw new ResponseException(code, RespCode.BECLOSING.getDesc());
        }
    }
}
